package com.firebird.app.kotlin.stock.trend.utils

import android.graphics.Bitmap
import java.util.*

/**
 * 网络图片的内存缓存对象
 * @author ljk
 * @date   2019年11月12日
 */
class MemoryCache {
    /**
     * 放入缓存时是个同步操作
     * LinkedHashMap构造方法的最后一个参数true代表这个map里的元素将按照最近使用次数由少到多排列，即LRU
     * 这样的好处是如果要将缓存中的元素替换，则先遍历出最近最少使用的元素来替换以提高效率
     */
    private val cache = Collections.synchronizedMap(LinkedHashMap<String, Bitmap>(10, 1.5f, true))
    /**
     * 缓存只能占用的最大堆内存
     */
    private var limit: Long = 1024000
    /**
     * 缓存中图片所占用的字节，初始0，将通过此变量严格控制缓存所占用的堆内存
     */
    private var size: Long = 0

    /**
     * 根据图片URL 查找缓存中的图片
     * @param imgUrl
     * @return
     */
    fun getBitmap(imgUrl: String?): Bitmap? {
        return try {
            if (!cache.containsKey(imgUrl)) {
                null
            } else cache[imgUrl]
            //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
        } catch (ex: NullPointerException) {
            ex.printStackTrace()
            null
        }
    }

    /**
     * 将从网络上获取的Bitmap加入缓存中
     * @param id
     * @param bitmap
     */
    fun put(imgUrl: String, bitmap: Bitmap?) {
        try {
            if (cache.containsKey(imgUrl)) {
                size -= getBitmapSize(cache[imgUrl])
            }
            cache[imgUrl] = bitmap
            size += getBitmapSize(bitmap)
            checkCackeSize()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 控制堆内存大小，超出最大值时按照LRU算法先替换掉最近最少使用的图片缓存
     */
    private fun checkCackeSize() {
        if (size > limit) {
            val iterator: MutableIterator<Map.Entry<String, Bitmap?>> = cache.entries.iterator()
            while (iterator.hasNext()) {
                val entry = iterator.next()
                size -= getBitmapSize(entry.value)
                iterator.remove()
                if (size <= limit) {
                    break
                }
            }
        }
    }

    /**
     * 获取图片占用的内存
     * @param bitmap
     * @return bitmap的二进制大小
     */
    private fun getBitmapSize(bitmap: Bitmap?): Long {
        return if (bitmap != null) {
            (bitmap.rowBytes * bitmap.height).toLong()
        } else 0
    }

    /**
     * 清空缓存
     */
    fun clear() {
        try { //NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
            cache.clear()
            size = 0
        } catch (ex: NullPointerException) {
            ex.printStackTrace()
        }
    }

    init {
        //缓存最大值为 运行时内存的四分之一
        limit = Runtime.getRuntime().maxMemory() / 4
    }
}